// 
//  Copyright © 2009 Jiří Zárevúcky <zarevucky.jiri@gmail.com>
// 
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as
//  published by the Free Software Foundation, either version 3 of the
//  License, or (at your option) any later version.
// 
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
// 
//  You should have received a copy of the GNU Affero General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
// 
// 


using System;

using Galaxium.Protocol.Xmpp.Library.Core;
using Galaxium.Protocol.Xmpp.Library.Extensions.Disco;
	
namespace Galaxium.Protocol.Xmpp.Library.Extensions
{
	public class ServiceEventArgs: EventArgs
	{
		public Service Service { get; private set; }
		
		public ServiceEventArgs (Service service)
		{
			Service = service;
		}
	}
	
	public class ServiceBrowser
	{
		public event EventHandler<ServiceEventArgs> ServiceReceived;
		public event EventHandler<StanzaErrorEventArgs> ErrorOccured;
		public event EventHandler Finished;
		
		private CoreStream _stream;
		private JabberID _jid;
		private int _waiting;
		
		public ServiceBrowser (CoreStream stream, JabberID jid)
		{
			_stream = stream;
			_jid = jid;
		}
		
		public void Request ()
		{
			var request = new ItemsRequest (_stream, _jid, null);
			request.ReceivedEvent += HandleReceivedEvent;
			request.ErrorEvent += (s, e) => OnErrorOccured (e.Error);
			request.Request ();
		}

		private void HandleReceivedEvent (object sender, EventArgs e)
		{
			var items = (sender as ItemsRequest).Result;
			
			_waiting = items.Count;
			
			foreach (var item in items) {
				var request = new InfoRequest (_stream, item.Jid, item.Node);
				request.ReceivedEvent += HandleInfoReceived;
				request.ErrorEvent += (s, a) => DecrementWaiting ();
				request.Request ();
			}
		}

		void HandleInfoReceived (object sender, EventArgs e)
		{
			var jid = (sender as InfoRequest).Jid;
			var node = (sender as InfoRequest).Node;
			var info = (sender as InfoRequest).Result;

			Action<bool> add_service = (registered) => {
				var service = new Service (jid, node, info, registered);
				OnServiceReceived (service);
				DecrementWaiting ();
			};
			
			if (info.Supports (Namespaces.Registration)) {	
				var reg = new Registration (_stream, jid);
				reg.FormReceived += (s, a) => add_service ((s as Registration).IsRegistered);
				reg.Failed += (s, a) => add_service (false);
				reg.RetrieveForm ();
			}
			else add_service (false);
		}
		
		private void DecrementWaiting ()
		{
			if (-- _waiting == 0 && Finished != null)
				Finished (this, EventArgs.Empty);
		}
		
		protected void OnServiceReceived (Service service)
		{
			if (ServiceReceived != null)
				ServiceReceived (this, new ServiceEventArgs (service));
		}
		
		protected void OnErrorOccured (StanzaError error)
		{
			if (ErrorOccured != null)
				ErrorOccured (this, new StanzaErrorEventArgs (error));
		}
	}
}
